// 定义 100 x 100 的底盘数据
// 使用 localStorage 获取，如果没有就新建一个
let map = localStorage['map'] ? JSON.parse(localStorage['map']) : Array(10000).fill(0);

// 是否动态显示 有动画效果
let tFlag = true;
let tRate = 0.3; // 阻塞延迟的概率 0-1
let logFlag = true; // 是否打印进行日志

// 获取 container 元素对象
let container;
let ballLenDom;
let pathLenDom;

let selectType = '';

let startP = [0, 0];
let endP = [0, 0];

window.onload = () => {
  container = document.getElementById('container');
  ballLenDom = document.getElementById('ballLen');
  setBallLen()

  pathLenDom = document.getElementById('pathLen');
  init()
}

// 设置墙体数
function setBallLen() {
  let i = 0;
  map.forEach(item => {
    i += item == 1 ? 1 : 0;
  })
  ballLenDom.innerText = i;
}

// 设置路径数
function setPathLen(len = 0) {
  pathLenDom.innerText = len;
}

// 初始
function init() {
  // 遍历所有格子
  for (let y = 0; y < 100; y++) {
    for (let x = 0; x < 100; x++) {
      // 创建地图方格
      let cell = document.createElement('div');
      cell.classList.add('cell');
      // 遇到格子的状态是 1 的，就赋予背景颜色
      if (map[100 * y + x] == 1) cell.style.backgroundColor = 'aqua';
      // 添加鼠标移动监听事件
      cell.addEventListener('mousemove', () => {
        // 只有在鼠标点击状态下执行
        if (mousedown) {
          if (clear) {
            // 1. 右键点击时，就是清楚格子的状态
            cell.style.backgroundColor = '';
            if (map[100 * y + x] != 0) setBallLen()
            map[100 * y + x] = 0;
          } else {
            // 2. 左键点击时，就是画入格子的状态
            cell.style.backgroundColor = 'aqua';
            if (map[100 * y + x] != 1) setBallLen()
            map[100 * y + x] = 1;
          }
        }
      });

      cell.addEventListener('dblclick', () => {
        if (selectType === 'start') {
          startP = [x, y];
          cell.style.backgroundColor = 'red';
        } else {
          endP = [x, y];
          cell.style.backgroundColor = 'yellow';
        }
      });
  // 加入到 container 之中
      container.appendChild(cell);
    }
  }

  let mousedown = false;
  let clear = false;

  // 鼠标按键点击时，把鼠标点击状态变为 true
  document.addEventListener('mousedown', e => {
    mousedown = true;
    clear = e.which === 3;
  });
  // 离开点击鼠标按键后，把状态更变成 false
  document.addEventListener('mouseup', () => (mousedown = false));
  // 因为我们需要使用右键，所以要把右键默认打开菜单禁用
  document.addEventListener('contextmenu', e => e.preventDefault());
}

// 等待函数
function sleep(t) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve,t);
  })
}

// 获取格与格之间的距离
function distance(point,end) {
  // 使用三角形 x^2 + y ^ 2 = z ^ 2 计算距离 当前点和终点的距离 距离越小 则表示最近
  // console.log(point, end, (point[0] - end[0]) ** 2 + (point[1] - end[1]) ** 2)
  return (point[0] - end[0]) ** 2 + (point[1] - end[1]) ** 2;
}

// 寻路方法
async function findPath(map, start ,end) {
  // 起点颜色
  // container.children[start[1] * 100 + start[0]].style.backgroundColor = 'red'
  // 终点颜色
  // container.children[end[1] * 100 + end[0]].style.backgroundColor = 'yellow'

  // 用于记录 上一个路径 新的数组 防止 影响到源数据
  const table = Object.create(map)
  // 初始化队列 包含了 起点
  // var queue = [start];
  let queue = new Sorted([start], (a,b) => {
    const x1Arec = distance(a,end);
    const x2Arec = distance(b,end);
    // console.log(`   x1:${a[0]},y1:${a[1]} x2:${b[0]},y2:${b[1]} => x1Arec:${x1Arec} - x2Arec:${x2Arec} = ${x1Arec - x2Arec}`)
    return x1Arec - x2Arec;
  });

  let i = 0;
  
  // 入队 
  async function insert(x,y,pre, t = 0) {
    if (x == start[0] && y == start[1]) return ;

    // 超出边界 直接停止
    if (x < 0 || x >= 100 || y < 0 || y >= 100) return ;
    // 遇到地图的墙  停止 墙是 0- 100 列行的数组 所以 y * 100 + x
    if (table[y * 100 + x]) return ;

    // 加入30  毫秒的停顿
    if (t) await sleep(1);

    // 给搜索到的路径格子加个背景颜色
    container.children[y * 100 + x].style.backgroundColor = 'DARKSLATEBLUE';

    // 标记走过的格子的值，标记为上一个格子的 x,y位置
    table[y * 100 + x] = pre;
    queue.give([x,y]);
    // queue.push([x,y])
    i++;
  }

  
  // 循环格子4边
  while (queue.length) {
    // 给一个距离终点最近的点
    let [x, y] = queue.take();
    if(logFlag) console.log(` 当前最近的点：${x}, ${y}}，长度：${queue.length}`)
    // let [x,y] = queue.shift()

    // 终点可以返回
    if ( x === end[0] && y === end[1]) {    
      // 起点颜色
      container.children[start[1] * 100 + start[0]].style.backgroundColor = 'red'

      // 进行逆推 退回来就可以得到最佳路线
      const path = [];
      let pathX = x;
      let pathY = y;
      while (pathX != start[0] || pathY != start[1]) {
        const index = pathY * 100 + pathX;
        if (table[index] && typeof table[index] == 'object') {
          pathX = table[index][0]
          pathY = table[index][1]
          path.push([pathX,pathY]);
          container.children[index].style.backgroundColor = 'fuchsia'
        }
      }

      // 终点颜色
      container.children[end[1] * 100 + end[0]].style.backgroundColor = 'yellow'

      if(logFlag) console.log('路径长度：', path.length, '总迭代次数：'+i)
      setPathLen(path.length);
      window.path = path;
      // while (x != start[0] || y != start[1]) {
      //   path.push(map[y * 100 + x])
      //   console.log(map[y * 100 + x])
      //   [x,y] = table[y * 100 + x];
      // }
      

      return true;
    }

    // 方向 上下左右 顺时针  应该是 左 上 此处可以加优化 判断哪个方向
    await insert(x - 1, y, [x,y], t = tFlag && Math.random() < tRate ? 1 : 0) // 左
    await insert(x, y - 1, [x,y], t = tFlag && Math.random() < tRate ? 1 : 0) // 上
    await insert(x + 1, y, [x,y], t = tFlag && Math.random() < tRate ? 1 : 0) // 右
    await insert(x, y + 1, [x,y], t = tFlag && Math.random() < tRate ? 1 : 0) // 下
  }
}

// 清除颜色
function clearColor() {
  // 遍历所有格子
  for (let y = 0; y < 100; y++) {
    for (let x = 0; x < 100; x++) {
      const dom = container.children[y * 100 + x]
      if(map[y * 100 + x] != 1) {
        dom.style.backgroundColor = '#2d2f42'
      }
    }
  }
}

/**
 * 设置起点
 */
function setStart() {
  selectType = 'start';
}

/**
 * 设置终点
 */
function setEnd () {
  selectType = 'end';
}


// 开始
function start() {
  clearColor()

  // let s = [0,0]
  // let e = [0,0]
  // let i = 0;
  // do {
  //   s = [Math.floor(Math.random() * 100), Math.floor(Math.random() * 100)]
  //   e = [Math.floor(Math.random() * 100), Math.floor(Math.random() * 100)]

  //   // 不能出现在有墙体 且 开始点 和 结束点不能相同
  //   if (
  //     map[s[0] * 100 + s[1] * 100] != 1
  //     && map[e[0] * 100 + e[1] * 100] != 1
  //     && s != e
  //   ) {
  //     break;
  //   }

  //   if ( i > 100 * 100)
  //   {
  //     alert("无落脚点")
  //     return;
  //   }

  //   i++;
  // } while(true)
  
  // if (logFlag) console.log(`起点：${s} 终点：${e}` )
  findPath(map, startP, endP)
}